package com.myspring.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * ClassName: TranscationProxyFactory
 * Package: com.myspring.utils
 * Description:
 *
 * @Author 刘英杰
 * @Create 2025/2/4 12:43
 * @Version 1.0
 */

@Component
public class TranscationProxyFactory {

    @Autowired
    TransactionManager transactionManager;

    @Autowired
    ApplicationContext applicationContext;

    /**
     *
     * @param cls 传递过来被代理类的字节码
     * @return
     * 例如:传递过来ProductServiceImpl.class,将来该方法就返回ProductServiceImpl代理类对象
     */
    public Object createProxyInstance(Class cls) {
        if (cls.getInterfaces().length != 0) {//判断传递过来的被代理类是否实现接口,如果实现采用JDK动态代理方式
            return Proxy.newProxyInstance(cls.getClassLoader(),
                    cls.getInterfaces(),
                    new InvocationHandler() {
                        /**
                         * @param proxy  底层生成代理类对象
                         * @param method 通过代理类对象调用的方法封装成method对象
                         * @param args   通过代理类对象调用的方法传递的参数
                         * @return
                         * @throws Throwable
                         */
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            Object retVal = null;
                            if (!method.getName().startsWith("find")) { //如果通过代理类对象调用的方法不是find开头的方法(查询相关)
                                //我们才加入事务控制
                                try {
                                    transactionManager.beginTransaction();
                                    //applicationContext.getBean(cls),applicationContext.getBean(cls根据Bean的类型去获取该Bean
                                    retVal = method.invoke(applicationContext.getBean(cls), args);//假如cls=ProductServiceImpl.class
                                    // productServiceImpl.增删改方法;
                                    transactionManager.commit();
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    transactionManager.rollback();
                                } finally {
                                    transactionManager.release();
                                }
                            }
                            return retVal;
                        }
                    });
        }else {     //该类没有实现任何接口,使用CGLIB动态代理
            //1.利用Enhancer增强被代理类,通过它生成代理类
            Enhancer enhancer = new Enhancer();
            //2.设置代理类的父类
            enhancer.setSuperclass(cls);
            //3.设置回调函数,当通过代理类对象调用方法,转调回调函数
            enhancer.setCallback(new MethodInterceptor() {
                /**
                 *
                 * @param proxy 代理类对象
                 * @param method 通过代理类对象调用的方法封装成的Method对象
                 * @param args 通过代理类对象调用的方法传递的参数
                 * @param methodProxy 底层生成的代理类代理的方法
                 * @return
                 * @throws Throwable
                 */
                @Override
                public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                    Object retVal = null;
                    if (!method.getName().startsWith("find")) { //如果通过代理类对象调用的方法不是find开头的方法(查询相关)
                        //我们才加入事务控制
                        try {
                            transactionManager.beginTransaction();
                            //applicationContext.getBean(cls),applicationContext.getBean(cls根据Bean的类型去获取该Bean
                            retVal = method.invoke(applicationContext.getBean(cls), args);//假如cls=ProductServiceImpl.class
                            // productServiceImpl.增删改方法;
                            transactionManager.commit();
                        } catch (Exception e) {
                            e.printStackTrace();
                            transactionManager.rollback();
                        } finally {
                            transactionManager.release();
                        }
                    }
                    return retVal;
                }
            });
            return enhancer.create();
        }

    }
}
